pub mod sms;
pub mod ocr;

use serde_derive::Deserialize;
use std::collections::HashMap;

use chrono::Utc;
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use serde_json::Value; 

use super::{my_err::MyErr, util, util_string};

#[allow(dead_code)]
const CONTENT_TYPE_URL: &str = "application/x-www-form-urlencoded";
#[allow(dead_code)]
const CONTENT_TYPE_JSON: &str = "application/json; charset=utf-8";
const CONTENT_TYPE_STREAM: &str = "application/octet-stream";

#[derive(Deserialize)]
pub struct Aliyun {
    pub access_key_id: String,
    pub access_key_secret: String,
    pub algorithm: String,
}

impl Aliyun { 

    /// 处理数据并发送请求返回结果
    async fn request_payload(
        &self,
        http_method: reqwest::Method,
        canonical_uri: &str,
        headers: &mut HeaderMap,
        query_param: HashMap<String, String>,
        body_string: String,
        _body_json: serde_json::Map<String, Value>,
        body_binary: Vec<u8>,
    ) -> Result<Value, MyErr> {
        // 得到当前时间，这里不必使用 utc 时间格式
        let now = Utc::now();

        // 设置数据头
        let date_v =
            HeaderValue::from_str(&now.format("%Y-%m-%dT%H:%M:%SZ").to_string()).map_err(|_| MyErr::Msg("参数错误！".to_string()))?;
        let nonce_v = HeaderValue::from_str(&util::random_str(8)).map_err(|_| MyErr::Msg("参数错误！".to_string()))?;
        headers.insert("x-acs-date", date_v);
        headers.insert("x-acs-signature-nonce", nonce_v);

        // 对 query 参数进行加密

        // 1.先对参数进行排序
        let mut query_map: Vec<(&String, &String)> = query_param.iter().collect();
        query_map.sort_by_key(|x| x.0);

        // 2.把参数转为URL格式（aaa=111&bbb=222&ccc=333）
        let mut canonical_query_string = serde_urlencoded::to_string(query_map).unwrap_or_default();

        // 3.替换参数字符串里的特定字符
        canonical_query_string = percent_code(&canonical_query_string);

        //println!("\n\n\n ncanonicalQueryString ===> {} \n\n\n", canonical_query_string);

        //println!("\n\n\n req.body ===> {} \n\n\n", req.body);

        // 对 body 数据进行加密
        let hashed_request_payload = if body_binary.len() > 0 {
            util_string::sha256_binary(&body_binary)
        } else {
            util_string::sha256(&body_string)
        };

        //println!("\n\n\n hashed_request_payload ===> {} \n\n\n", hashed_request_payload);

        // 设置 body 加密后的至入head
        let hashed_request_payload_v = HeaderValue::from_str(&hashed_request_payload).map_err(|_| MyErr::Msg("参数错误！".to_string()))?;
        headers.insert("x-acs-content-sha256", hashed_request_payload_v);

        // 对 headers 值进行加密
        let mut canonical_headers = String::from("");
        let mut signed_headers = String::from("");

        // 1.先对 headers 中的值进行排序
        let mut headers_map: Vec<(&HeaderName, &HeaderValue)> = headers.iter().collect();
        headers_map.sort_by_key(|x| x.0.as_str());

        // 2.拼凑字符串
        for (k, v) in headers_map {
            let k_low = k.as_str().to_lowercase();
            if k_low == "host" || k_low.starts_with("x-acs-") || k_low == "content-type" {
                canonical_headers.push_str(&k_low);
                canonical_headers.push_str(":");
                canonical_headers.push_str(v.to_str().unwrap_or_default());
                canonical_headers.push_str("\n");

                signed_headers.push_str(&k_low);
                signed_headers.push_str(";");
            }
        }

        // 3.去掉尾部的 ; 符号
        signed_headers = signed_headers.trim_end_matches(";").to_string();

        //println!("\n\n\n canonical_headers ===> \n{} \n\n", canonical_headers);
        //println!("\n\n\n signed_headers ===> \n{} \n\n", signed_headers);

        // 拼凑待加密字符串
        //req.httpMethod + "\n" + req.canonicalUri + "\n" + canonicalQueryString + "\n" + canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload
        let canonical_request = format!(
            "{}\n{}\n{}\n{}\n{}\n{}",
            http_method, canonical_uri, canonical_query_string, canonical_headers, signed_headers, hashed_request_payload
        );
        //println!("\n\n\n canonical_request ===> \n{} \n\n", canonical_request);

        // 加密
        let hashed_canonical_request = util_string::sha256(&canonical_request);
        let string_to_sign = format!("{}\n{}", self.algorithm, hashed_canonical_request);
        //println!("\n\n\n string_to_sign ===> \n{} \n\n", string_to_sign);

        // 加密
        let signature = util_string::hmac_sha256(&self.access_key_secret, &string_to_sign);
        //println!("\n\n\n signature ===> \n{} \n\n", signature);

        let authorization = format!(
            "{} Credential={},SignedHeaders={},Signature={}",
            self.algorithm, self.access_key_id, signed_headers, signature
        );
        //println!("\n\n\n authorization ===> \n{} \n\n", authorization);

        let authorization_v = HeaderValue::from_str(&authorization).map_err(|_| MyErr::Msg("参数错误！".to_string()))?;
        headers.insert("Authorization", authorization_v);

        let host = headers.get("host").map(|v| v.to_str().unwrap_or("")).unwrap_or_default();
        let content_type = headers.get("content-type").map(|v| v.to_str().unwrap_or("")).unwrap_or_default();

        //println!("\n\n\n content_type ===> \n{} \n\n", content_type);

        // 得到url地址
        let url = format!("https://{}{}?{}", host, canonical_uri, canonical_query_string);

        let rs = if content_type == CONTENT_TYPE_STREAM {
            let client = reqwest::Client::new();
            let rs = client.request(http_method, url).headers(headers.clone()).body(body_binary).send().await;
            match rs {
                Ok(res) => {
                    match res.json::<serde_json::Value>().await {
                    Ok(v) => Ok(v),
                    Err(e) => {
                        log::error!("读取URL数据失败！错误：{:?}  ", e);
                        Err(MyErr::Msg("网络异常！".to_string()))
                    }
                }
            },
                Err(e) => {
                    log::error!("连接url地址失败！错误：{:?}   ", e);
                    Err(MyErr::Msg("网络异常！".to_string()))
                }
            }
        } else {
            let client = reqwest::Client::new();
            let rs = client.request(http_method, url).headers(headers.clone()).form(&query_param).body(body_string).send().await;
            match rs {
                Ok(res) => match res.json::<serde_json::Value>().await {
                    Ok(v) => Ok(v),
                    Err(e) => {
                        log::error!("读取URL数据失败！错误：{:?}  ", e);
                        Err(MyErr::Msg("网络异常！".to_string()))
                    }
                },
                Err(e) => {
                    log::error!("连接url地址失败！错误：{:?}   ", e);
                    Err(MyErr::Msg("网络异常！".to_string()))
                }
            }
        };

        return rs;
    }
}

/// 替换特殊字符
fn percent_code(str: &str) -> String {
    // 替换特定的编码字符
    let mut s = str.to_string();
    s = s.replace("+", "%20");
    s = s.replace("*", "%2A");
    s = s.replace("%7E", "~");
    return s;
}
